`
https://leetcode.cn/problems/random-flip-matrix/
`

class Solution {
  constructor(m, n) {
    this.m = m
    this.n = n
    this.len = m * n
    // 已删除元素到尾部未删除元素的映射
    this.deletedToExist = new Map();
    // 这个 deletedToExist 存的到底是什么呢？举个例子你就明白了：
    // 假设数组 [1,2,3,4,5]，我第一次随机选择了元素 2，
    // 然后我就会在 deletedToExist 记录一个映射 2 -> 5，并删除最后的元素 5
    // 现在数组是 [1,2,3,4]，我第二次随机选择又选到了 2，
    // 但不能重复选择同一个元素，所以我选择 5，因为 deletedToExist[2] = 5
    // 然后我再更新 deletedToExist，记录 2 -> 4 并删除最后的元素 4
    // 以此类推，这样就能保证随机选择到相同的元素时也能等概率地返回不同的元素
  }

  flip() {
    // 获取随机数
    let rand = this._rand()
    let res = rand
    // 如果获取到的随机数用过了，就拿到对应的映射
    if (this.deletedToExist.has(res)) {
      res = this.deletedToExist.get(res)
    }
    // 拿到最后的一个数
    let last = this.len - 1
    // 尾部的数也可能用过了
    if (this.deletedToExist.has(last)) {
      last = this.deletedToExist.get(last)
    }
    // res 这里会用掉，建立新映射给新的最后一个数
    this.deletedToExist.set(rand, last)
    // 删掉最后一个数
    this.len--
    // 转换为二维坐标返回
    return [Math.floor(res / this.n), res % this.n]
  }

  reset() {
    this.len = this.m * this.n
    this.deletedToExist.clear()
  }

  _rand() {
    return Math.floor(Math.random() * this.len)
  }
}

/** 
* Your Solution object will be instantiated and called as such:
* var obj = new Solution(m, n)
* var param_1 = obj.flip()
* obj.reset()
*/

// test
const solution = new Solution(3, 1);
console.log(solution.flip())  // 返回 [1, 0]，此时返回 [0,0]、[1,0] 和 [2,0] 的概率应当相同
console.log(solution.flip())  // 返回 [2, 0]，因为 [1,0] 已经返回过了，此时返回 [2,0] 和 [0,0] 的概率应当相同
console.log(solution.flip())  // 返回 [0, 0]，根据前面已经返回过的下标，此时只能返回 [0,0]
console.log(solution.reset()) // 所有值都重置为 0 ，并可以再次选择下标返回
console.log(solution.flip())  // 返回 [2, 0]，此时返回 [0,0]、[1,0] 和 [2,0] 的概率应当相同